package com.myk.game.gobangchess.rooms.oldrooms;

import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.rooms.absrooms.AbsOneTwoTwoTwoStepRoom;
import com.myk.game.gobangchess.signs.TextSign;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.utils.SignsUtils;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.ColorSign;
import java.util.*;
import java.util.List;

/**
 * 四色格围接棋
 */
public class GoLinkFourColorRoom extends AbsOneTwoTwoTwoStepRoom {

    private DrawIndexRecord drawIndexRecord;
    private int[][] colorGrids; //棋盘格子颜色
    private int[] firstPoint; // 记录第一个落子位置
    private static final int BOARD_SIZE = 16;
    private static final int[] COLORS = {1, 2, 3, 4}; // 蓝绿黄红四种颜色
    private static final int BLACK = 1; // 黑方棋子
    private static final int WHITE = 2; // 白方棋子

    public GoLinkFourColorRoom(String roomName) {
        super(roomName, "在围接棋基础上，采用六子棋的落子机制，在随机生成的四色棋盘上对弈。", "四色格围接棋" , GridsUtils.createEmptyGrids(BOARD_SIZE, BOARD_SIZE), true, true);
        
        generateColorBoard(); // 生成初始四色棋盘
    }

    @Override
    public String getRuleText() {
        return "《四色格围接棋》\n" +
                "使用16×16格的棋盘，棋盘随机分布等量的蓝绿黄红四种颜色格\n" +
                "黑方先下一子，之后黑白双方轮流下两个棋子（黑棋和白棋）\n" +
                "落下两个棋子必须落到到两个相同颜色的格子，无法落子判负\n" +
                "吃子与禁入规则均同围棋\n" +
                "先以直线两两相连的棋子连通两条对边的一方获胜";
    }

    /**
     * 获取游戏信息 - 用于前端显示和状态同步
     * 包含棋盘状态、颜色提示、游戏提示等完整信息
     * @return 格式化的游戏信息字符串
     */
    @Override
    public String getGameInfo() {
        signList.clear(); // 清空之前的标记


        // 绘制彩色棋盘背景 - 根据colorGrids显示蓝绿黄红四种颜色
        for (int row = 0; row < BOARD_SIZE; row++) {
            for (int col = 0; col < BOARD_SIZE; col++) {
                String colorHex = getColorHex(colorGrids[row][col]);
                signList.add(new ColorSign(getIndex(row, col), colorHex));
            }
        }

        // 添加棋盘边框
        signList.add(new GroundSign(getIndex(0, 0), getIndex(BOARD_SIZE - 1, BOARD_SIZE - 1), ColorCost.TRANSPARENT, ColorCost.BOARD_LINE, 1.5f, 0, 0));

        // 添加可落子位置高亮提示
        int targetColor = getTargetColor();
        if (targetColor != -1) {
            // 高亮显示所有可落子的目标颜色格子
            for (int row = 0; row < BOARD_SIZE; row++) {
                for (int col = 0; col < BOARD_SIZE; col++) {
                    if (colorGrids[row][col] != targetColor && curGrids[row][col] == 0) {
                        signList.add(new GroundSign(getIndex(row, col),  ColorCost.GRAY_TRANSLUCENT,ColorCost.TRANSPARENT, 1f, 0, 0));
                    }
                }
            }
        }

        // 添加 最近落子提示
        if (drawIndexRecord != null){
            if (drawIndexRecord.firstIndex != -1){
                signList.add(new TextSign(drawIndexRecord.firstIndex, "※", ColorCost.RED_TEXT));
            }
            if (drawIndexRecord.secondIndex != -1){
                signList.add(new TextSign(drawIndexRecord.secondIndex, "※", ColorCost.RED_TEXT));
            }
        }

        // 添加游戏提示文字
        updateGameTip();

        // 返回标准格式的游戏信息
        return super.getGameInfo();
    }

    /**
     * 游戏准备回调方法 - 当两位玩家都准备好后，游戏最开始时调用
     * 负责初始化四色棋盘和重置游戏状态
     */
    @Override
    protected void onStartPrepare() {
        // 确保colorGrids已初始化
        if (colorGrids == null) {
            colorGrids = new int[BOARD_SIZE][BOARD_SIZE];
        }
        drawIndexRecord = new DrawIndexRecord();
        generateColorBoard(); // 生成16×16随机四色棋盘
        updateGameTip(); // 更新游戏提示信息
        noticeBlackMove(); //通知黑方先行
    }

    /**
     * 重置棋盘方法 - 清空所有棋子并重新生成四色棋盘
     * 通常在重新开始游戏时调用
     */
    @Override
    public void resetGrids() {
        super.resetGrids(); // 调用父类重置方法清空棋子

        // 初始化颜色网格（如果尚未初始化）
        if (colorGrids == null) {
            colorGrids = new int[BOARD_SIZE][BOARD_SIZE];
        }

        drawIndexRecord = null;
        generateColorBoard(); // 重新生成新的四色棋盘
        firstPoint = null; // 重置第一个落子位置
        secondPoint = null; // 重置第二个落子位置
    }

    /**
     * 玩家落子处理主方法 - 处理玩家点击落子的逻辑
     * 根据四色连子游戏规则：
     * 1. 黑方和白方轮流落子（1222制：黑1→白2→黑2→白2...）
     * 2. 必须选择与当前目标颜色相同的格子（黑方第一步除外）
     * 3. 两个同色格子连通后形成一条连线
     * 4. 先连通两条对边的玩家获胜
     * 
     * @param row 落子的行坐标（0-15，左上角为0,0）
     * @param col 落子的列坐标（0-15，左上角为0,0）
     * @param value 落子方（1=黑方，2=白方）
     */
    @Override
    public void doRule(int row, int col, int value) {

        // 检查格子是否已被占用
        if (curGrids[row][col] != 0) {
            return;
        }
        
        // 检查颜色匹配规则
        if (!canPlaceAtColor(row, col)) {
            return;
        }
        
        // 检查自杀点（禁入点）
        if (isSuicideMove(row, col, value)) {
            return;
        }
        
        // 正确的1222落子制实现
        curGrids[row][col] = value;
        drawIndexRecord.record(value, getIndex(row, col));
        
        // 执行吃子操作
        int capturedCount = captureStones(row, col, value);
        if (capturedCount > 0) {
            noticeAllBroadcast("吃掉了" + capturedCount + "个棋子");
        }
        
        if (step == 0) {
            // 黑方第一步：落1子后立即切换
            stepAdd();
            noticeChangeMove();
        } else {
            // 1222规则：step > 0时，每回合落2子
            if (firstPoint == null) {
                // 每回合的第一个棋子
                firstPoint = new int[]{row, col};
                updateTempPointSigns();
                noticeAllRefreshGameInfo();
            } else {
                // 每回合的第二个棋子（必须与第一个同色）
                secondPoint = new int[]{row, col};
                updateTempPointSigns();
                stepAdd();
                
                // 重置落子标记
                firstPoint = null;
                secondPoint = null;
                
                WinState winState = checkWin(row, col);
                if (winState != null) {
                    doOver(winState.winMode, winState.winMsg);
                } else {
                    // 落完2子后才切换玩家
                    noticeChangeMove();
                }
            }
        }
    }

    /**
     * 检查胜利条件 - 游戏的核心胜利判定逻辑
     * @param row 最新落子的行坐标
     * @param col 最新落子的列坐标
     * @return 胜利状态对象，包含胜利方和胜利原因，null表示游戏继续
     */
    @Override
    protected WinState checkWin(int row, int col) {
        // 检查连通对边的胜利条件：黑方或白方连通两条对边
        if (checkConnectOppositeSides(BLACK)) {
            return new WinState(WinMode.BLACK_WIN, "黑方连通两条对边获胜！");
        }
        if (checkConnectOppositeSides(WHITE)) {
            return new WinState(WinMode.WHITE_WIN, "白方连通两条对边获胜！");
        }

        // 检查无法落子的情况：当一方无合法落子位置时判负
        if (checkNoValidMoves()) {
            if (cur == 1) {
                return new WinState(WinMode.WHITE_WIN, "黑方无法落子，白方获胜！");
            } else {
                return new WinState(WinMode.BLACK_WIN, "白方无法落子，黑方获胜！");
            }
        }

        return null; // 游戏继续
    }

    private void updateGameTip() {
        if (cur == 0){
            gameTip = "-1";
            return;
        }
        if (step == 0) {
            gameTip = "黑方先手，请落一子到任意色格";
        } else if (firstPoint == null) {
            gameTip = (cur == 1 ? "黑方" : "白方") + "第一步，请落第一个棋子到任意色格";
        } else{
            int targetColor = colorGrids[firstPoint[0]][firstPoint[1]];
            gameTip = (cur == 1 ? "黑方" : "白方") + "第二步，请再落一子到" + getColorName(targetColor) + "格";
        }
    }

    /**
     * 生成16×16随机四色棋盘
     * 确保蓝、绿、黄、红四种颜色等量分布（每种64个格子）
     * 使用随机打乱算法确保颜色分布的随机性
     */
    private void generateColorBoard() {
        colorGrids = new int[BOARD_SIZE][BOARD_SIZE]; // 创建新的颜色棋盘数组
        List<Integer> colorList = new ArrayList<>(); // 存储所有颜色值的列表
        
        // 创建等量分布的颜色列表（每种颜色64个格子）
        int totalCells = BOARD_SIZE * BOARD_SIZE; // 总格子数：256个
        int eachColorCount = totalCells / 4; // 每种颜色64个格子
        
        // 填充颜色列表
        for (int color : COLORS) {
            for (int i = 0; i < eachColorCount; i++) {
                colorList.add(color);
            }
        }
        
        // 随机打乱颜色分布，确保随机性
        Collections.shuffle(colorList);
        
        // 将打乱后的颜色填充到棋盘中
        int index = 0;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                colorGrids[i][j] = colorList.get(index++);
            }
        }
    }
    
    public int getColorAt(int row, int col) {
        if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE) {
            return colorGrids[row][col];
        }
        return 0;
    }
    
    /**
     * 获取颜色的中文名称，用于游戏提示显示
     * @param color 颜色值（1-4）
     * @return 对应的中文颜色名称
     */
    public String getColorName(int color) {
        switch (color) {
            case 1: return "蓝色";
            case 2: return "绿色";
            case 3: return "黄色";
            case 4: return "红色";
            default: return "无色";
        }
    }

    /**
     * 检查指定位置是否可以落子（颜色匹配检查）
     * 
     * 规则：
     * - 黑方第一步(step=0)：无颜色限制
     * - 每回合的第一个棋子：无颜色限制
     * - 每回合的第二个棋子：必须与第一个棋子所在格子的颜色相同
     * 
     * @param row 行坐标
     * @param col 列坐标
     * @return 是否可以落子
     */
    private boolean canPlaceAtColor(int row, int col) {
        int targetColor = getTargetColor();
        if (targetColor == -1) {
            return true; // 黑方第一步或每回合第一个棋子无限制
        }
        return colorGrids[row][col] == targetColor;
    }
    
    /**
     * 获取当前落子的目标颜色
     * 
     * 规则：
     * - 黑方第一步(step=0)：返回-1（无限制）
     * - 每回合的第一个棋子：返回-1（无限制）
     * - 每回合的第二个棋子：返回第一个棋子所在格子的颜色
     * 
     * @return 目标颜色值，-1表示无限制
     */
    private int getTargetColor() {
        if (step == 0) {
            return -1; // 黑方第一步无限制
        }
        if (firstPoint == null) {
            return -1; // 每回合的第一个棋子无限制
        }
        // 第二个棋子必须与第一个棋子同色
        return colorGrids[firstPoint[0]][firstPoint[1]];
    }
    
    /**
     * 创建当前棋盘的深度副本
     * 用于临时分析时不影响原棋盘状态
     * @return 当前棋盘的完整副本
     */
    private int[][] copyBoard() {
        int[][] copy = new int[BOARD_SIZE][BOARD_SIZE];
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                copy[i][j] = curGrids[i][j];
            }
        }
        return copy;
    }

    /**
     * 检查是否为自杀点（禁入点）
     * 根据围棋规则，如果落子后会导致己方棋子无气，则为自杀点
     * 但如果落子后能吃掉对方棋子，则不算自杀点
     * @param row 落子行坐标
     * @param col 落子列坐标
     * @param player 落子玩家（1=黑方，2=白方）
     * @return true表示是自杀点，不能落子
     */
    private boolean isSuicideMove(int row, int col, int player) {
        int[][] tempBoard = copyBoard();
        tempBoard[row][col] = player;
        
        // 先检查是否能吃掉对方棋子
        int opponent = player == 1 ? 2 : 1;
        int capturedCount = 0;
        
        // 检查四个方向上的对方棋子
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        
        for (int[] dir : directions) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            
            if (newRow >= 0 && newRow < BOARD_SIZE && newCol >= 0 && newCol < BOARD_SIZE) {
                if (tempBoard[newRow][newCol] == opponent) {
                    boolean[][] visited = new boolean[BOARD_SIZE][BOARD_SIZE];
                    if (!hasLiberty(tempBoard, newRow, newCol, opponent, visited)) {
                        // 能吃掉对方棋子，不算自杀点
                        return false;
                    }
                }
            }
        }
        
        // 检查落子后己方棋子是否有气（只有在不能吃子的情况下）
        boolean[][] visited = new boolean[BOARD_SIZE][BOARD_SIZE];
        return !hasLiberty(tempBoard, row, col, player, visited);
    }
    
    /**
     * 检查指定位置的棋子是否有气（围棋规则）
     * @param board 当前棋盘状态
     * @param row 棋子行坐标
     * @param col 棋子列坐标
     * @param player 棋子所属玩家
     * @param visited 访问标记数组
     * @return true表示有气，false表示无气
     */
    private boolean hasLiberty(int[][] board, int row, int col, int player, boolean[][] visited) {
        if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE || visited[row][col]) {
            return false;
        }
        
        if (board[row][col] == 0) {
            return true; // 空位置，有气
        }
        
        if (board[row][col] != player) {
            return false; // 对方棋子，无气
        }
        
        visited[row][col] = true;
        
        // 检查上下左右四个方向
        boolean hasLib = hasLiberty(board, row-1, col, player, visited) ||
                         hasLiberty(board, row+1, col, player, visited) ||
                         hasLiberty(board, row, col-1, player, visited) ||
                         hasLiberty(board, row, col+1, player, visited);
        
        return hasLib;
    }
    
    /**
     * 检查并执行吃子操作（围棋规则）
     * 落子后检查周围对方棋子是否无气，无气的棋子被吃掉
     * @param row 最新落子的行坐标
     * @param col 最新落子的列坐标
     * @param player 落子玩家
     * @return 被吃掉的棋子数量
     */
    private int captureStones(int row, int col, int player) {
        int capturedCount = 0;
        int opponent = player == 1 ? 2 : 1;
        
        // 检查四个方向上的对方棋子
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        
        for (int[] dir : directions) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            
            if (newRow >= 0 && newRow < BOARD_SIZE && newCol >= 0 && newCol < BOARD_SIZE) {
                if (curGrids[newRow][newCol] == opponent) {
                    boolean[][] visited = new boolean[BOARD_SIZE][BOARD_SIZE];
                    if (!hasLiberty(curGrids, newRow, newCol, opponent, visited)) {
                        capturedCount += removeGroup(newRow, newCol, opponent);
                    }
                }
            }
        }
        
        return capturedCount;
    }
    
    /**
     * 移除无气的棋子组
     * @param row 棋子组起始行坐标
     * @param col 棋子组起始列坐标
     * @param player 棋子所属玩家
     * @return 被移除的棋子数量
     */
    private int removeGroup(int row, int col, int player) {
        if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE || curGrids[row][col] != player) {
            return 0;
        }
        
        curGrids[row][col] = 0; // 移除棋子
        int count = 1;
        
        // 递归移除相连的棋子
        count += removeGroup(row-1, col, player);
        count += removeGroup(row+1, col, player);
        count += removeGroup(row, col-1, player);
        count += removeGroup(row, col+1, player);
        
        return count;
    }

    /**
     * 获取颜色的十六进制表示，用于前端显示
     * @param color 颜色值（1-4）
     * @return 对应的十六进制颜色字符串
     */
    private String getColorHex(int color) {
        switch (color) {
            case 1: return "#8880BFFF"; // 柔和半透明蓝色 - 天蓝高亮
            case 2: return "#8880D580"; // 柔和半透明绿色 - 薄荷绿高亮
            case 3: return "#88FFD480"; // 柔和半透明黄色 - 暖黄高亮
            case 4: return "#88FFB3D9"; // 更红的半透明粉红色高亮
            default: return "#00000000"; // 透明
        }
    }
    
    /**
     * 检查玩家是否连通两条对边（胜利条件）
     * @param player 玩家颜色（1=黑方，2=白方）
     * @return true表示该玩家已连通两条对边
     */
    private boolean checkConnectOppositeSides(int player) {
        // 分别检查上下边连通和左右边连通
        boolean topBottomConnected = checkTopBottomConnection(player);
        boolean leftRightConnected = checkLeftRightConnection(player);
        
        return topBottomConnected || leftRightConnected;
    }
    
    /**
     * 检查上下两条对边的连通性
     * @param player 玩家颜色
     * @return true表示该玩家的棋子连通上下边
     */
    private boolean checkTopBottomConnection(int player) {
        boolean[] topVisited = new boolean[BOARD_SIZE]; // 记录上边界棋子
        boolean[] bottomVisited = new boolean[BOARD_SIZE]; // 记录下边界棋子
        
        // 标记上边界（第0行）的该玩家棋子
        for (int col = 0; col < BOARD_SIZE; col++) {
            if (curGrids[0][col] == player) {
                topVisited[col] = true;
            }
        }
        
        // 标记下边界（第15行）的该玩家棋子
        for (int col = 0; col < BOARD_SIZE; col++) {
            if (curGrids[BOARD_SIZE-1][col] == player) {
                bottomVisited[col] = true;
            }
        }
        
        // 检查任意上边界棋子与任意下边界棋子的连通性
        for (int topCol = 0; topCol < BOARD_SIZE; topCol++) {
            if (topVisited[topCol]) {
                for (int bottomCol = 0; bottomCol < BOARD_SIZE; bottomCol++) {
                    if (bottomVisited[bottomCol]) {
                        if (isConnected(0, topCol, BOARD_SIZE-1, bottomCol, player)) {
                            return true;
                        }
                    }
                }
            }
        }
        
        return false;
    }
    
    /**
     * 检查左右两条对边的连通性
     * @param player 玩家颜色
     * @return true表示该玩家的棋子连通左右边
     */
    private boolean checkLeftRightConnection(int player) {
        boolean[] leftVisited = new boolean[BOARD_SIZE]; // 记录左边界棋子
        boolean[] rightVisited = new boolean[BOARD_SIZE]; // 记录右边界棋子
        
        // 标记左边界（第0列）的该玩家棋子
        for (int row = 0; row < BOARD_SIZE; row++) {
            if (curGrids[row][0] == player) {
                leftVisited[row] = true;
            }
        }
        
        // 标记右边界（第15列）的该玩家棋子
        for (int row = 0; row < BOARD_SIZE; row++) {
            if (curGrids[row][BOARD_SIZE-1] == player) {
                rightVisited[row] = true;
            }
        }
        
        // 检查任意左边界棋子与任意右边界棋子的连通性
        for (int leftRow = 0; leftRow < BOARD_SIZE; leftRow++) {
            if (leftVisited[leftRow]) {
                for (int rightRow = 0; rightRow < BOARD_SIZE; rightRow++) {
                    if (rightVisited[rightRow]) {
                        if (isConnected(leftRow, 0, rightRow, BOARD_SIZE-1, player)) {
                            return true;
                        }
                    }
                }
            }
        }
        
        return false;
    }
    
    /**
     * 使用广度优先搜索检查两点之间的连通性
     * @param startRow 起始行坐标
     * @param startCol 起始列坐标
     * @param endRow 目标行坐标
     * @param endCol 目标列坐标
     * @param player 玩家颜色
     * @return true表示两点之间存在连通路径
     */
    private boolean isConnected(int startRow, int startCol, int endRow, int endCol, int player) {
        boolean[][] visited = new boolean[BOARD_SIZE][BOARD_SIZE];
        Queue<int[]> queue = new LinkedList<>();
        
        // 起始点必须是该玩家的棋子
        if (curGrids[startRow][startCol] != player) {
            return false;
        }
        
        // 广度优先搜索初始化
        queue.offer(new int[]{startRow, startCol});
        visited[startRow][startCol] = true;
        
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 四个移动方向
        
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int row = current[0];
            int col = current[1];
            
            // 到达目标点
            if (row == endRow && col == endCol) {
                return true;
            }
            
            // 搜索四个方向的相邻格子
            for (int[] dir : directions) {
                int newRow = row + dir[0];
                int newCol = col + dir[1];
                
                // 检查边界和是否已访问，且必须是该玩家的棋子
                if (newRow >= 0 && newRow < BOARD_SIZE && newCol >= 0 && newCol < BOARD_SIZE &&
                    !visited[newRow][newCol] && curGrids[newRow][newCol] == player) {
                    visited[newRow][newCol] = true;
                    queue.offer(new int[]{newRow, newCol});
                }
            }
        }
        
        return false; // 未找到连通路径
    }
    
    /**
     * 检查当前玩家是否无合法落子位置
     * @return true表示无合法落子，游戏结束
     */
    private boolean checkNoValidMoves() {
        int targetColor = getTargetColor();
        
        // 遍历整个棋盘寻找可落子位置
        for (int row = 0; row < BOARD_SIZE; row++) {
            for (int col = 0; col < BOARD_SIZE; col++) {
                if (curGrids[row][col] == 0) { // 空格子
                    // 检查颜色匹配
                    if (targetColor == -1 || colorGrids[row][col] == targetColor) {
                        return false; // 找到可落子位置，游戏继续
                    }
                }
            }
        }
        
        return true; // 无有效落子位置，游戏结束
    }

    public static class DrawIndexRecord{

        int side = 0;
        int firstIndex = -1;
        int secondIndex = -1;

        public void record(int side,int index){
            if (this.side != side){
                this.side = side;
                this.firstIndex = index;
                this.secondIndex = -1;
            }
            else {
                this.secondIndex = index;
            }
        }
    }
}
